﻿    using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TCC_Hotel.Repositorio;
using TCC_Hotel.Entidades;
using System.Web.Caching;

namespace TCC_Hotel.Serviços.BDServices
{
    public class ReservaService
    {
        ReservaRepositorio repositorio = new ReservaRepositorio();

        /// <summary>
        /// Serviço para inserir uma reserva de hóspede particular nos bancos
        /// </summary>
        /// <param name="funcionario">reserva que será inserida</param>
        /// <returns>True se foi inserido ou false se nao</returns>
        public bool EfetuarReservaParticular(Reserva_Particular reserva)
        {
            return repositorio.EfetuarReservaParticular(reserva);

        }

         /// <summary>
        /// Serviço para editar uma reserva de hóspede particular nos bancos
        /// </summary>
        /// <param name="funcionario">reserva que será inserida</param>
        /// <returns>True se foi editado ou false se nao</returns>
        public bool EditarReservaParticular(Reserva_Particular reserva, int ID)
        {
            return repositorio.EditarReservaParticular(reserva, ID);

        }

        /// <summary>
        /// Serviço para dar check uma reserva de hóspede particular faturado nos bancos
        /// </summary>
        /// <param name="funcionario">reserva que será inserida</param>
        /// <returns>True se foi editado ou false se nao</returns>
        public bool CheckReservaParticular(bool Status, int ID)
        {
            return repositorio.CheckReservaParticular(Status, ID);

        }

           /// <summary>
        /// Serviço para dar check uma reserva de hóspede faturado nos bancos
        /// </summary>
        /// <param name="funcionario">reserva que será inserida</param>
        /// <returns>True se foi editado ou false se nao</returns>
        public bool CheckReservaFaturada(bool Status, int ID)
        {
            return repositorio.CheckReservaFaturada(Status, ID);

        }
         /// <summary>
        /// Serviço para editar uma reserva de hóspede faturado nos bancos
        /// </summary>
        /// <param name="funcionario">reserva que será inserida</param>
        /// <returns>True se foi editado ou false se nao</returns>
        public bool EditarReservaFaturada(Reserva_Faturada reserva, int ID)
        {
            return repositorio.EditarReservaFaturada(reserva, ID);

        }
        
        /// <summary>
        /// Serviço para inserir uma reserva de hóspede faturado nos bancos
        /// </summary>
        /// <param name="funcionario">reserva que será inserida</param>
        /// <returns>True se foi inserido ou false se nao</returns>
        public bool EfetuarReservaFaturada(Reserva_Faturada reserva)
        {
            return repositorio.EfetuarReservaFaturada(reserva);

        }
        
        /// <summary>
        /// Serviço para listar todos as reservas particulares do banco
        /// </summary>
        /// <returns>Lista com as reservas particulares do banco</returns>
        public List<Reserva_Particular> RecuperarReservasParticulares()
        {
            return repositorio.RecuperarReservasParticulares();

        }

        /// <summary>
        /// Serviço para listar todos as reservas particulares de um apartamento do banco
        /// </summary>
        /// <returns>Lista com as reservas particulares de um apartamento do banco</returns>
        public List<Reserva_Particular> RecuperarReservasParticularesApartamento(int apartamento)
        {
            return repositorio.RecuperarReservasParticularesApartamento(apartamento);

        }

        /// <summary>
        /// Serviço para listar todos as reservas particulares de um apartamento do banco
        /// </summary>
        /// <returns>Lista com as reservas particulares de um apartamento do banco</returns>
        public List<Reserva_Faturada> RecuperarReservasFaturadasApartamento(int apartamento)
        {
            return repositorio.RecuperarReservasFaturadasApartamento(apartamento);

        }

        /// <summary>
        /// recupera detalhes de uma reserva específica
        /// </summary>
        /// <returns>Reserva particular específica</returns>
        public Reserva_Particular RecuperarDetalhesReservaParticular(int ID)
        {
            return repositorio.RecuperarDetalhesReservaParticular(ID);

        }

        /// <summary>
        /// recupera detalhes de uma reserva específica
        /// </summary>
        /// <returns>Reserva faturada específica</returns>
        public Reserva_Faturada RecuperarDetalhesReservaFaturada(int ID)
        {
            return repositorio.RecuperarDetalhesReservaFaturada(ID);

        }

        /// <summary>
        /// Serviço para listar todos as reservas faturadas do banco
        /// </summary>
        /// <returns>Lista com as reservas faturadas do banco</returns>
        public List<Reserva_Faturada> RecuperarReservasFaturadas()
        {
            return repositorio.RecuperarReservasFaturadas();

        }

        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de Reserva Particular</returns>
        public List<Reserva_Particular> ListarReservasParticularesCache()
        {
            List<Reserva_Particular> listaReservasParticulares = new List<Reserva_Particular>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Reserva_Particular") == null)
            {
                //Consulta os hóspedes faturados no banco
                listaReservasParticulares = RecuperarReservasParticulares();

                //Armazena a lista de hóspedes faturados em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Reserva_Particular", listaReservasParticulares, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                listaReservasParticulares = (List<Reserva_Particular>)HttpContext.Current.Cache.Get("Lista_Reserva_Particular");
            }
            return listaReservasParticulares;
        }

        /// <summary>
        /// Verifica se a informação ja esta gravada em cache, se tiver recupera, 
        /// senao faz a consulta e grava em cache
        /// </summary>
        /// <returns>Lista de Reserva faturadas</returns>
        public List<Reserva_Faturada> ListarReservasFaturadasCache()
        {
            List<Reserva_Faturada> listaReservasfaturadas = new List<Reserva_Faturada>();

            //Verifica se a informação esta guardada em cache
            if (HttpContext.Current.Cache.Get("Lista_Reserva_Faturada") == null)
            {
                //Consulta os hóspedes faturados no banco
                listaReservasfaturadas = RecuperarReservasFaturadas();

                //Armazena a lista de hóspedes faturados em cache de 5 minutos para evitar muitas consultas ao banco
                HttpContext.Current.Cache.Add("Lista_Reserva_Faturada", listaReservasfaturadas, null,
                                 DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.High, null);


            }

           //caso essa informaçao ja estiver no cache
            else
            {
                //Resgata informação do cache
                listaReservasfaturadas = (List<Reserva_Faturada>)HttpContext.Current.Cache.Get("Lista_Reserva_Faturada");
            }
            return listaReservasfaturadas;
        }

        /// <summary>
        /// Metodo que retorna um array com as datas que estao reservadas e o nome da pessoa que 
        /// realizou a reserva
        /// </summary>
        /// <returns>Lista com datas e nomes</returns>
        public List<DiaNomeReserva> ListarDiasReservas(List<Reserva_Particular> listaReservas_Particulares, List<Reserva_Faturada> listaReservas_faturadas)
        {
            List<DiaNomeReserva> listaRetorno = new List<DiaNomeReserva>();

            //pega os dias reservados das reservas particulares
            foreach (var i in listaReservas_Particulares)
            {
                TimeSpan dias = i.Data_Final - i.Data_Inicio;
                for (int j = 0; j <= dias.Days; j++)
                {
                    // adiciona todos os dias do período na lista de retorno
                    listaRetorno.Add(new DiaNomeReserva()
                    {
                        Data = i.Data_Inicio.AddDays(j),
                        Nome = i.Nome_Reserva,
                        TipoHospede = 1,
                        NoHotel = i.NoHotel

                    });

                }
            }

            //pega os dias reservados das reservas faturadas
            foreach (var i in listaReservas_faturadas)
            {
                TimeSpan dias = i.Data_Final - i.Data_Inicio;
                for (int j = 0; j <= dias.Days; j++)
                {
                    // adiciona todos os dias do período na lista de retorno
                    listaRetorno.Add(new DiaNomeReserva()
                    {
                        Data = i.Data_Inicio.AddDays(j),
                        Nome = i.Empresa_Reserva,
                        TipoHospede = 2,
                        NoHotel = i.NoHotel
                    });

                }
            }


            return listaRetorno;
        }

        /// <summary>
        /// Verifica se a data de fim não é menor que o inicio
        /// </summary>
        /// <param name="dataInicio">string no formato dateTime para a data de inicio</param>
        /// <param name="dataFim">string no formato dateTime para a data de fim</param>
        /// <returns>true se esta correta, false se não esta</returns>
        public bool VerificaDatas(string dataInicio, string dataFim)
        {
            try
            {
                TimeSpan dias = Convert.ToDateTime(dataFim) - Convert.ToDateTime(dataInicio);
                TimeSpan diasRetroativos = DateTime.Now - Convert.ToDateTime(dataInicio);
                DateTime agora = DateTime.Now;

                if (dias.Days >= 0)
                {
                    if (!(diasRetroativos.Days > 0))
                    {
                        return true;
                    }
                    else
                    {
                        //se o hospede chegar apos a meia noite 
                        if (agora.AddDays(-1).Date == Convert.ToDateTime(dataInicio) && agora.Hour >= 0 && agora.Hour < 12)
                        {
                            return true;
                        }

                        return false;
                    }
                }
                else
                    return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Verifica se o periodo esta disponivel no apartamento
        /// </summary>
        /// <param name="dataInicio">string no formato dateTime para a data de inicio</param>
        /// <param name="dataFim">string no formato dateTime para a data de fim</param>
        /// <param name="listaDiasReservas">Lista com as datas ocupadas</param>
        /// <returns>true se esta disponivel, false se não esta</returns>
        public bool VerificaDisponibilidade(string dataInicio, string dataFim, List<DiaNomeReserva> listaDiasReservas)
        {
            DateTime inicio = Convert.ToDateTime(dataInicio);
            DateTime fim = Convert.ToDateTime(dataFim);
            List<DateTime> datasDesejadas = new List<DateTime>();
            
            TimeSpan dias = fim - inicio;

            //adiciona o periodo todo em uma lista de datas
            for (int j = 0; j <= dias.Days; j++)
            {
                datasDesejadas.Add(inicio.AddDays(j));
            }

            //Verifica se alguma data desejada já esta na lista de reservas
            foreach (var i in listaDiasReservas)
            {
                if (datasDesejadas.Contains(i.Data))
                {
                    return false;
                }

            }
            return true;
        }

        /// <summary>
        /// Verifica se o periodo esta disponivel no apartamento e a ultima data disponivel para extender a reserva
        /// </summary>
        /// <param name="dataInicio">string no formato dateTime para a data de inicio</param>
        /// <param name="dataFim">string no formato dateTime para a data de fim</param>
        /// <param name="listaDiasReservas">Lista com as datas ocupadas</param>
        /// <returns>ultima data disponivel para expandir reservas</returns>
        public string VerificaUltimaDataDisponivel(string dataInicio, string dataFim, List<DiaNomeReserva> listaDiasReservas)
        {
            DateTime inicio = Convert.ToDateTime(dataInicio);
            DateTime fim = Convert.ToDateTime(dataFim).AddDays(-1);
            List<DateTime> datasDesejadas = new List<DateTime>();

            TimeSpan dias = fim - inicio;

            //adiciona o periodo todo em uma lista de datas
            for (int j = 0; j <= dias.Days; j++)
            {
                datasDesejadas.Add(inicio.AddDays(j));
            }

            //Verifica se alguma data desejada já esta na lista de reservas
            foreach (var i in listaDiasReservas)
            {
                if (datasDesejadas.Contains(i.Data))
                {
                    return Convert.ToString(i.Data).Substring(0, 10);
                }

            }
            return "true";
        }

        /// <summary>
        /// Serviço para excluir reservas antigas
        /// </summary>
        /// <returns>true se cancelou e false se nao</returns
        public void ExcluirReservasAntigas(int QuantidadeDiasExclusao)
        {
            DateTime DiaLimite = DateTime.Now.AddDays(-1 * QuantidadeDiasExclusao);

            //chama o repositorio que exclui as reservas
            repositorio.CancelarReservasAntigasFaturada(DiaLimite);
            repositorio.CancelarReservasAntigasParticular(DiaLimite);
        }


        /// <summary>
        /// Serviço para cancelar uma reserva 
        /// </summary>
        /// <returns>true se cancelou e false se nao</returns
        public bool CancelarReservaParticular(int ID)
        {
            return repositorio.CancelarReservaParticular(ID);
        }

        /// <summary>
        /// Serviço para cancelar uma reserva 
        /// </summary>
        /// <returns>true se cancelou e false se nao</returns
        public bool CancelarReservaFaturada(int ID)
        {
            return repositorio.CancelarReservaFaturada(ID);
        }

        /// <summary>
        /// Serviço que verifica quantos hóspedes estão na reserva 
        /// </summary>
        /// <returns>quantidade de hóspede na reserva</returns
        public int QuantidadeHospedeReservaParticular(int ID)
        {
            Reserva_Particular reserva = RecuperarDetalhesReservaParticular(ID);
            int quantidade = 1;

            if (!String.IsNullOrEmpty(reserva.Nome_2))            
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_3))
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_4))
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_5))
                quantidade++; 



            return quantidade;
        }

        /// <summary>
        /// Serviço que verifica quantos hóspedes estão na reserva 
        /// </summary>
        /// <returns>quantidade de hóspede na reserva</returns
        public int QuantidadeHospedeReservaFaturada(int ID)
        {
            Reserva_Faturada reserva = RecuperarDetalhesReservaFaturada(ID);
            int quantidade = 0;

            if (!String.IsNullOrEmpty(reserva.Nome_1))
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_2))
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_3))
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_4))
                quantidade++;
            if (!String.IsNullOrEmpty(reserva.Nome_5))
                quantidade++;



            return quantidade;
        }

        /// <summary>
        /// Serviço para filtrar o dropdown de apartamento com os que tem vaga para o período desejado 
        /// </summary>
        /// <returns>Lista com os apartamentos livres</returns
        public List<Apartamento> FiltrarApartamentosPorPeriodo(int numeroHospedes, string Inicio, string Final)
        {
            ApartamentoService servico_Apartamento = new ApartamentoService();
            List<Apartamento> apartamentosTotais = servico_Apartamento.ListarApartamentosCache().Where(i => i.QntMaximaHospedes == numeroHospedes).ToList();
            List<Apartamento> apartamentosFiltrados = new List<Apartamento>();

            foreach (var j in apartamentosTotais)
            {
                List<Reserva_Particular> listaReservas_Particulares = ListarReservasParticularesCache().Where(i => i.Numero_Apartamento == j.Numero).ToList();
                List<Reserva_Faturada> listaReservas_Faturadas = ListarReservasFaturadasCache().Where(i => i.Numero_Apartamento == j.Numero).ToList();
                List<DiaNomeReserva> listaDiasReservas = ListarDiasReservas(listaReservas_Particulares, listaReservas_Faturadas);

                if (VerificaDisponibilidade(Inicio, Final, listaDiasReservas))
                {
                    //adiciona na lista apenas os apartamentos com disponibilidade no período
                    apartamentosFiltrados.Add(j);
                }
            
            }


            return apartamentosFiltrados;
        }

    }
}